package com.easychat.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;

import com.easychat.entity.dto.MessageSendDTO;
import com.easychat.entity.dto.SysSettingDto;
import com.easychat.entity.enums.*;
import com.easychat.entity.po.*;
import com.easychat.entity.query.*;
import com.easychat.exception.BusinessException;
import com.easychat.mappers.*;
import com.easychat.utils.CopyTools;
import com.easychat.utils.RedisUtil;
import com.easychat.websocket.ChannelContextUtils;
import com.easychat.websocket.MessageHandler;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.catalina.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.easychat.entity.vo.PaginationResultVO;
import com.easychat.service.UserContactApplyService;
import com.easychat.utils.StringTools;
import org.springframework.transaction.annotation.Transactional;


/**
 *  业务接口实现
 */
@Service("userContactApplyService")
public class UserContactApplyServiceImpl implements UserContactApplyService {

	@Resource
	private UserContactApplyMapper<UserContactApply, UserContactApplyQuery> userContactApplyMapper;

	@Resource
	private UserContactMapper<UserContact, UserContactQuery> userContactMapper;

	@Resource
	private ChatSessionUserMapper<ChatSessionUser, ChatSessionUserQuery> chatSessionUserMapper;

	@Resource
	private ChatSessionMapper<ChatSession, ChatSessionQuery> chatSessionMapper;

	@Resource
	private UserInfoMapper<UserInfo, UserInfoQuery> userInfoMapper;

	@Resource
	private ChatMessageMapper<ChatMessage, ChatMessageQuery> chatMessageMapper;

	@Resource
	private GroupInfoMapper<GroupInfo, GroupInfoQuery> groupInfoMapper;

	@Resource
	private ChannelContextUtils channelContextUtils;

	@Resource
	private RedisUtil redisUtil;
    @Autowired
    private MessageHandler messageHandler;

	/**
	 * 根据条件查询列表
	 */
	@Override
	public List<UserContactApply> findListByParam(UserContactApplyQuery param) {
		return this.userContactApplyMapper.selectList(param);
	}

	/**
	 * 根据条件查询列表
	 */
	@Override
	public Integer findCountByParam(UserContactApplyQuery param) {
		return this.userContactApplyMapper.selectCount(param);
	}

	/**
	 * 分页查询方法
	 */
	@Override
	public PaginationResultVO<UserContactApply> findListByPage(UserContactApplyQuery param) {
		int count = this.findCountByParam(param);
		int pageSize = param.getPageSize() == null ? PageSize.SIZE15.getSize() : param.getPageSize();

		SimplePage page = new SimplePage(param.getPageNo(), count, pageSize);
		param.setSimplePage(page);
		List<UserContactApply> list = this.findListByParam(param);
		PaginationResultVO<UserContactApply> result = new PaginationResultVO(count, page.getPageSize(), page.getPageNo(), page.getPageTotal(), list);
		return result;
	}

	/**
	 * 新增
	 */
	@Override
	public Integer add(UserContactApply bean) {
		return this.userContactApplyMapper.insert(bean);
	}

	/**
	 * 批量新增
	 */
	@Override
	public Integer addBatch(List<UserContactApply> listBean) {
		if (listBean == null || listBean.isEmpty()) {
			return 0;
		}
		return this.userContactApplyMapper.insertBatch(listBean);
	}

	/**
	 * 批量新增或者修改
	 */
	@Override
	public Integer addOrUpdateBatch(List<UserContactApply> listBean) {
		if (listBean == null || listBean.isEmpty()) {
			return 0;
		}
		return this.userContactApplyMapper.insertOrUpdateBatch(listBean);
	}

	/**
	 * 多条件更新
	 */
	@Override
	public Integer updateByParam(UserContactApply bean, UserContactApplyQuery param) {
		StringTools.checkParam(param);
		return this.userContactApplyMapper.updateByParam(bean, param);
	}

	/**
	 * 多条件删除
	 */
	@Override
	public Integer deleteByParam(UserContactApplyQuery param) {
		StringTools.checkParam(param);
		return this.userContactApplyMapper.deleteByParam(param);
	}

	/**
	 * 根据ApplyId获取对象
	 */
	@Override
	public UserContactApply getUserContactApplyByApplyId(Integer applyId) {
		return this.userContactApplyMapper.selectByApplyId(applyId);
	}

	/**
	 * 根据ApplyId修改
	 */
	@Override
	public Integer updateUserContactApplyByApplyId(UserContactApply bean, Integer applyId) {
		return this.userContactApplyMapper.updateByApplyId(bean, applyId);
	}

	/**
	 * 根据ApplyId删除
	 */
	@Override
	public Integer deleteUserContactApplyByApplyId(Integer applyId) {
		return this.userContactApplyMapper.deleteByApplyId(applyId);
	}

	@Override
	public PageInfo<UserContactApply> selectApplyPage(Integer pageNo, Integer pageSize, String userId) {
		PageHelper.startPage(pageNo, pageSize);
		List<UserContactApply> applyList = this.userContactApplyMapper.selectApplyPage(pageNo, pageSize, userId);
		return PageInfo.of(applyList);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void dealWithApply(String userId, Integer applyId, Integer status) {
		UserContactApplyStatusEnum statusEnum = UserContactApplyStatusEnum.getByStatus(status);

		if (null == statusEnum || statusEnum.equals(UserContactApplyStatusEnum.INIT)) {
			throw new BusinessException(ResponseCodeEnum.CODE_600);
		}

		UserContactApply applyInfo = this.userContactApplyMapper.selectByApplyId(applyId);

		if (null == applyId || !applyInfo.getReceiveUserId().equals(userId)) {
			throw new BusinessException(ResponseCodeEnum.CODE_600);
		}

		Integer count = userContactApplyMapper.updateApplyStatus(applyId, status);

		if (count == 0) {
			throw new BusinessException(ResponseCodeEnum.CODE_600);
		}

		// 如果通过了
		if (UserContactApplyStatusEnum.PASS.getStatus().equals(status)) {
			this.addContact(applyInfo.getApplyUserId(), applyInfo.getReceiveUserId(), applyInfo.getContactId(), applyInfo.getContactType(), applyInfo.getApplyInfo());
			return;
		}

		// 加入黑名单
		if (UserContactApplyStatusEnum.BLACKLIST.getStatus().equals(status)) {
			Date curDate = new Date();
			UserContact userContact = new UserContact();
			userContact.setUserId(applyInfo.getApplyUserId());
			userContact.setContactId(applyInfo.getContactId());
			userContact.setContactType(applyInfo.getContactType());
			userContact.setCreateTime(curDate);
			userContact.setLastUpdateTime(curDate);
			userContact.setStatus(UserContactStatusEnum.BLACKLIST_BE_FIRST.getStatus());

			userContactMapper.insertOrUpdate(userContact);
		}

		// 拒绝
		if (UserContactApplyStatusEnum.REJECT.getStatus().equals(status)) {
			UserContactApply query = new UserContactApply();
			query.setStatus(UserContactApplyStatusEnum.REJECT.getStatus());
			query.setLastApplyTime(System.currentTimeMillis());
			userContactApplyMapper.updateByApplyId(query, applyId);
		}

	}

	@Override
	public void addContact(String applyUserId, String receiveUserId, String contactId, Integer contactType, String applyInfo) {
		// 先判断群聊人数
		if (UserContactTypeEnum.GROUP.getType().equals(contactType)) {
			UserContactQuery userContactQuery = new UserContactQuery();
			userContactQuery.setContactId(contactId);
			userContactQuery.setStatus(UserContactStatusEnum.FRIEND.getStatus());
			Integer count = userContactMapper.selectCount(userContactQuery);
			SysSettingDto sysSetting = redisUtil.getSysSetting();
			if (count >= sysSetting.getMaxGroupCount()) {
				// 成员已经满了
				throw new BusinessException("群聊成员已满");
			}
		}
		Date curDate = new Date();
		// 同意，双方添加好友
		List<UserContact> contactList = new ArrayList<>();
		// 申请人添加对方
		UserContact applyUserContact = UserContact.builder()
				.userId(applyUserId)
				.contactId(contactId)
				.contactType(contactType)
				.createTime(curDate)
				.lastUpdateTime(curDate)
				.status(UserContactStatusEnum.FRIEND.getStatus())
				.build();
		contactList.add(applyUserContact);
		// 如果是申请好友，接收人添加申请人，群组不用添加对方为好友
		if (UserContactTypeEnum.USER.getType().equals(contactType)) {
			applyUserContact = UserContact.builder()
					.userId(receiveUserId)
					.contactId(applyUserId)
					.contactType(contactType)
					.createTime(curDate)
					.lastUpdateTime(curDate)
					.status(UserContactStatusEnum.FRIEND.getStatus())
					.build();
			contactList.add(applyUserContact);
		}
		// 批量插入
		userContactMapper.insertOrUpdateBatch(contactList);
		if (UserContactTypeEnum.USER.getType().equals(contactType)) {
			redisUtil.addUserContact(receiveUserId, applyUserId);
		}
		redisUtil.addUserContact(applyUserId, contactId);

		// 创建会话
		String sessionId = null;
		if (UserContactTypeEnum.USER.getType().equals(contactType)) {
			sessionId = StringTools.getChatSessionId4User(new String[] {applyUserId, contactId});
		} else {
			sessionId = StringTools.getChatSessionId4Group(contactId);
		}

		List<ChatSessionUser> chatSessionUserList = new ArrayList<>();
		if (UserContactTypeEnum.USER.getType().equals(contactType)) {
			ChatSession chatSession = new ChatSession();
			chatSession.setSessionId(sessionId);
			chatSession.setLastMessage(applyInfo);
			chatSession.setLastReceiveTime(curDate.getTime());
			this.chatSessionMapper.insertOrUpdate(chatSession);

			// 申请人session
			ChatSessionUser applySessionUser = new ChatSessionUser();
			applySessionUser.setUserId(applyUserId);
			applySessionUser.setContactId(contactId);
			applySessionUser.setSessionId(sessionId);
			String applyUserNickName = this.userInfoMapper.selectByUserId(contactId).getNickName();
			applySessionUser.setContactName(applyUserNickName);
			chatSessionUserList.add(applySessionUser);

			// 接收人session
			ChatSessionUser receiveSessionUser = new ChatSessionUser();
			receiveSessionUser.setUserId(contactId);
			receiveSessionUser.setContactId(applyUserId);
			receiveSessionUser.setSessionId(sessionId);
			receiveSessionUser.setContactName(this.userInfoMapper.selectByUserId(applyUserId).getNickName());
			chatSessionUserList.add(receiveSessionUser);

			this.chatSessionUserMapper.insertBatch(chatSessionUserList);

			// 记录消息
			ChatMessage chatMessage = ChatMessage.builder()
					.sessionId(sessionId)
					.messageType(MessageTypeEnum.CHAT.getType())
					.messageContent(applyInfo)
					.sendUserId(applyUserId)
					.sendUserNickName(applyUserNickName)
					.sendTime(curDate.getTime())
					.contactId(contactId)
					.contactType(UserContactTypeEnum.USER.getType())
					.build();
			this.chatMessageMapper.insert(chatMessage);

			// 发出消息
			MessageSendDTO sendDTO = CopyTools.copy(chatMessage, MessageSendDTO.class);
			// 发给接受还有申请的人
			messageHandler.sendMessage(sendDTO);

			// 发给申请人,发送人就是接收人，申请人就是接收人，反过来
			sendDTO.setMessageType(MessageTypeEnum.ADD_FRIEND_SELF.getType());
			sendDTO.setContactId(applyUserId);
			sendDTO.setExtendData(this.userInfoMapper.selectByUserId(contactId));
			messageHandler.sendMessage(sendDTO);

		} else {
			// 加组
			GroupInfo groupInfo = this.groupInfoMapper.selectByGroupId(contactId);
			ChatSessionUser chatSessionUser = ChatSessionUser.builder()
					.userId(applyUserId)
					.contactId(contactId)
					.contactName(groupInfo.getGroupName())
					.sessionId(sessionId)
					.build();

			this.chatSessionUserMapper.insertOrUpdate(chatSessionUser);

			UserInfo userInfo = this.userInfoMapper.selectByUserId(applyUserId);
			String message = String.format(MessageTypeEnum.ADD_GROUP.getInitMessage(), userInfo.getNickName());

			ChatSession chatSession = ChatSession.builder()
					.sessionId(sessionId)
					.lastReceiveTime(curDate.getTime())
					.lastMessage(message)
					.build();
			this.chatSessionMapper.insertOrUpdate(chatSession);

			ChatMessage chatMessage = ChatMessage.builder()
					.sessionId(sessionId)
					.messageType(MessageTypeEnum.ADD_GROUP.getType())
					.messageContent(message)
					.sendTime(curDate.getTime())
					.contactId(contactId)
					.contactType(UserContactTypeEnum.GROUP.getType())
					.status(MessageStatusEnum.SENDED.getStatus())
					.build();
			this.chatMessageMapper.insert(chatMessage);

			// 将群组添加到联系人
			redisUtil.addUserContact(groupInfo.getGroupOwnerId(), groupInfo.getGroupId());

			// 将联系人添加到群组通道
			channelContextUtils.addUser2Group(groupInfo.getGroupOwnerId(), groupInfo.getGroupId());

			MessageSendDTO messageSendDTO = CopyTools.copy(chatMessage, MessageSendDTO.class);
			messageSendDTO.setContactId(contactId);

			UserContactQuery userContactQuery = new UserContactQuery();
			userContactQuery.setContactId(contactId);
			userContactQuery.setStatus(UserContactStatusEnum.FRIEND.getStatus());
			Integer count = this.userContactMapper.selectCount(userContactQuery);
			messageSendDTO.setMemberCount(count);
			messageSendDTO.setContactName(groupInfo.getGroupName());
			messageHandler.sendMessage(messageSendDTO);
		}

	}
}